import os

from jsonpath_ng import parse
import pytest
from src.excelHandler import ExcelHandler
from src.http_client import HttpClient
from src.logger import logger

@pytest.fixture(scope="session")
def http_client():
    """创建Session级HTTP客户端，自动执行登录并注入Token"""
    client = HttpClient()
    logger.info("HTTP客户端初始化完成，开始执行登录流程")

    try:
        # 1. 从HttpClient的配置中读取登录参数（复用已有的config读取逻辑）
        api_config = client.config["API"]  # HttpClient的__init__已加载config.ini
        login_url = api_config.get("login_url")
        username = api_config.get("login_username")
        password = api_config.get("login_password")
        token_header = api_config.get("token_header_key", "Authorization")  # 默认Authorization
        token_prefix = api_config.get("token_prefix", "Bearer")  # 默认Bearer
        token_json_path = api_config.get("token_json_path", "data.token")  # 默认data.token

        # 校验登录配置是否齐全
        if not all([login_url, username, password, token_json_path]):
            raise ValueError(
                "config.ini的[API]节点缺少登录必要配置！需包含："
                "login_url、login_username、login_password、token_json_path"
            )

        # 2. 构造登录请求体（根据你的登录接口格式调整，如form-data/json）
        # （示例：若登录接口是JSON格式，用json=login_data；若是form-data，改用data=login_data）
        login_data = {
            "username": username,  # 需与你的登录接口参数键一致（如有的是account）
            "password": password
        }

        # 3. 发送登录请求（复用HttpClient的send_request，自动拼接base_url）
        login_response = client.send_request(
            method="POST",
            url=login_url,
            json=login_data  # 按实际接口格式调整（json/data）
        )

        # 4. 校验登录响应（状态码非2xx则抛出异常）
        login_response.raise_for_status()  # 触发HTTP错误（如401账号错、500服务错）

        # 5. 提取Token（用jsonpath解析配置的路径）
        login_json = login_response.json()
        jsonpath_expr = parse(token_json_path)
        token_result = [match.value for match in jsonpath_expr.find(login_json)]
        if not token_result or not isinstance(token_result[0], str):
            raise ValueError(
                f"登录响应中未提取到有效Token！\n"
                f"响应内容：{login_json}\n"
                f"解析路径：{token_json_path}"
            )
        token = token_result[0]  # 取列表第一个元素（实际Token值）

        # 5.结构简单的响应，token获取方式
        # login_json = login_response.json()
        # token = login_json["data"]["accessToken"]

        # 6. 将Token注入到Session全局Headers（后续所有请求自动携带）
        auth_header_value = f"{token_prefix} {token}" if token_prefix else token
        client.session.headers.update({token_header: auth_header_value})
        logger.info(f"登录成功！已设置全局Token：{token_header}: {auth_header_value}")

    except Exception as e:
        # 登录失败直接终止测试（无Token后续接口无法执行）
        logger.error(f"登录流程失败，终止所有测试：{str(e)}")
        client.close()  # 清理资源
        raise  # 抛出异常，中断pytest执行

    # 提供客户端实例给测试用例
    yield client

    # 测试结束后关闭会话
    client.close()
    logger.info("HTTP会话已关闭（含登录态）")

@pytest.fixture(scope="session")
def excel_handler():
    """创建Excel处理器实例"""
    handler = ExcelHandler()
    # handler.open()
    yield handler
    handler.close()


def pytest_generate_tests(metafunc):
    """动态生成测试用例"""
    """钩子函数，执行顺序优于夹具"""
    # 如果测试函数有test_case参数，则生成参数化测试用例
    if "test_case" in metafunc.fixturenames:
        # 获取命令行参数
        config = metafunc.config
        module_filter = config.getoption("--module")
        priority_filter = config.getoption("--priority")

        # 创建ExcelHandler实例（注意：这里不能使用fixture，因为pytest_generate_tests在fixture之前执行）
        handler = ExcelHandler()

        # 使用筛选条件获取测试用例
        test_cases = handler.get_cases(
            module=module_filter,
            priority=priority_filter
        )

        handler.close()

        # 参数化测试用例
        if test_cases:
            metafunc.parametrize(
                "test_case",
                test_cases,
                ids=[case.get("case_id", f"case_{i}") for i, case in enumerate(test_cases)]
            )
        else:
            # 如果没有符合条件的用例，跳过测试
            pytest.skip("没有找到符合条件的测试用例")

def pytest_addoption(parser):
    # 钩子函数，添加模块筛选参数，相当于对自定义的--module命令注册，执行顺序优于pytest_generate_tests
    parser.addoption(
        "--module",
        action="store",
        default=None,
        help="指定执行的模块（如：用户模块）"
    )
    # 添加优先级筛选参数
    parser.addoption(
        "--priority",
        action="store",
        default=None,
        help="指定执行的用例等级（如：P0）"
    )

@pytest.fixture(scope="session")
def cmd_options(request):
    """封装方便复用：将命令行参数转换为字典，供用例筛选使用"""
    return {
        "module": request.config.getoption("--module"),
        "priority": request.config.getoption("--priority")
    }